﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Collections;
using System.Data;
using CascadeDropDown.Library.Helpers;

namespace CascadeDropDown.Library.Component
{
    public abstract class ViewModelBase<TViewModel> where TViewModel : class,new()
    {
        public ViewModelBase()
        {
            getSecurityTable = new Dictionary<string, Func<bool>>();
            setSecurityTable = new Dictionary<string, Func<bool>>();

            datasourceList = new Dictionary<string, Func<object>>();


        }
        protected virtual bool DefaultAccess { get { return true; } }

        private Dictionary<string, Func<bool>> getSecurityTable { get; set; }
        private Dictionary<string, Func<bool>> setSecurityTable { get; set; }

        private Dictionary<string, Func<object>> datasourceList { get; set; }


        public object GetDatasourceFor(string propertyName)
        {
            //if (datasourceList.ContainsKey(propertyName))
            //{
            //    object data = datasourceList[propertyName];
            //    DataTable dTable = new DataTable();
            //    var enumrator = (data as IEnumerable).GetEnumerator();
            //    enumrator.MoveNext();
            //    enumrator.Current.GetType().GetProperties().
            //        ToList().ForEach(pr => dTable.Columns.Add(pr.Name, pr.PropertyType));
            //    foreach (var item in (data as IEnumerable))
            //    {
            //        DataRow newRow = dTable.NewRow();
            //        item.GetType().GetProperties().ToList().ForEach(pr => newRow[pr.Name] = pr.GetValue(item, null));
            //    }
            //    return dTable;
            //}
            return datasourceList.ContainsKey(propertyName) ? datasourceList[propertyName]() : null;
        }

        #region Public Methods
        //public void Allow(string propertyName)
        //{
        //    CreateAccessRule(propertyName, Component.AllowFor.Set | Component.AllowFor.Get, true);
        //}
        //public void Allow(string propertyName, AllowFor allowment)
        //{
        //    CreateAccessRule(propertyName, allowment, true);
        //}
        //public void Restrict(string propertyName)
        //{
        //    CreateAccessRule(propertyName, Component.AllowFor.Set | Component.AllowFor.Get, false);
        //}
        //public void Restrict(string propertyName, AllowFor allowment)
        //{
        //    CreateAccessRule(propertyName, allowment, false);
        //}

        public bool CanGet(string propertyName) { return getSecurityTable.ContainsKey(propertyName) ? getSecurityTable[propertyName]() : DefaultAccess; }
        public bool CanSet(string propertyName) { return setSecurityTable.ContainsKey(propertyName) ? setSecurityTable[propertyName]() : DefaultAccess; }

       

        #endregion

        public void RunBussiness()
        {
            PrepareBussiness();
            foreach (KeyValuePair<string, Func<bool>> setSecurityPair in setSecurityTable)
            {
                if (!setSecurityPair.Value())
                {
                    this.GetType().GetProperty(setSecurityPair.Key).
                        DoIf(me => me.GetSetMethod() != null, me=> me.SetValue(this,null,null));
                }
            }
        }

        protected abstract void PrepareBussiness();

        protected void CreateAccessRule(string propertyName, AllowFor allowment, Func<bool> allowMethod)
        {
            if ((allowment & Component.AllowFor.Get) > 0)
            {
                if (getSecurityTable.ContainsKey(propertyName))
                {
                    getSecurityTable[propertyName] = allowMethod;
                }
                else
                {
                    getSecurityTable.Add(propertyName, allowMethod);
                }
            }
            if ((allowment & Component.AllowFor.Set) > 0)
            {
                if (setSecurityTable.ContainsKey(propertyName))
                {
                    setSecurityTable[propertyName] = allowMethod;
                }
                else
                {
                    setSecurityTable.Add(propertyName, allowMethod);
                }
            }
        }
        protected void AddDatasource(string propertyName, Func<object> data) { datasourceList.Add(propertyName, data); }

        public bool HasDataSourceFor(string propertyName)
        {
            return datasourceList.ContainsKey(propertyName);
        }
    }

    public enum AllowFor
    {
        Get = 2,
        Set = 4
    }
}
